﻿using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Microsoft.Win32;
using Plugins.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System;
using System.Windows.Shapes;
using System.Windows.Input;

namespace Visualizer.Windows
{
    /// <summary>
    /// MainWindow class. 
    /// </summary>
	public partial class MainWindow
	{
        private static Brush _OrangeBrush = new SolidColorBrush(System.Windows.Media.Colors.Orange);
        private static Brush _WhiteBrush = new SolidColorBrush(System.Windows.Media.Colors.White);        
        private static OpenFileDialog _openDialog = new OpenFileDialog();       

        /// <summary>
        /// Initialize MainWindow
        /// </summary>
		public MainWindow()
		{
			this.InitializeComponent();            
		}

        /// <summary>
        /// Gets OpenFileDialog instance
        /// </summary>
        public OpenFileDialog OpenDialog
        {
            get { return _openDialog; }
        }

        /// <summary>
        /// Gets TreeListView instance used for showing XML
        /// </summary>
        public TreeListView View
        {
            get { return treeListView;}
        }

        /// <summary>
        /// Gets StatusBar instance
        /// </summary>
        public StatusBar StatusBar
        {
            get { return statusBar; }
        }

        /// <summary>
        /// Gets SelectBox used for changing active plugin
        /// </summary>
        public ComboBox PluginSelectBox
        {
            get { return pluginSelectBox; }
        }

        /// <summary>
        /// Gets or sets text showed in StatusBar instance
        /// </summary>
        public string StatusText
        {
            get { return (string)statusLabel.Content; }
            set { statusLabel.Content = value; }
        }

        /// <summary>
        /// Gets or set state circle color
        /// </summary>
        public Brush StateCircleColor
        {
            get { return stateCircle.Fill; }
            set { stateCircle.Fill = value; }
        }
        
        /// <summary>
        /// Gets or sets expression string
        /// </summary>
        public string ExpressionString
        {
            get
            {
                FlowDocument doc = expressionTextBox.Document;
                TextRange tr = new TextRange(doc.ContentStart, doc.ContentEnd);
                return tr.Text.Replace("\r", "")
                              .Replace("\n", "");                
            }

            set
            {
                expressionTextBox.BeginInit();

                Paragraph paragraph = new Paragraph();
                paragraph.Inlines.Add(value);
                expressionTextBox.Document.Blocks.Clear();
                expressionTextBox.Document.Blocks.Add(paragraph);

                expressionTextBox.EndInit();
            }
        }

        /// <summary>
        /// Gets RichtTextBox for expression writing
        /// </summary>
        public RichTextBox ExpressionTextBox
        {
            get { return expressionTextBox; }
        }

        /// <summary>
        /// Gets Evaluate button
        /// </summary>
        public Button EvaluateButton
        {
            get { return evaluateButton; }
        }

        /// <summary>
        /// Gets or sets evaluate button content
        /// </summary>
        public string EvaluateButtonContent
        {
            get { return evaluateButton.Content as string; }
            set { evaluateButton.Content = value; }
        }

        /// <summary>
        /// Gets plugin menu
        /// </summary>
        public MenuItem PluginMenu
        {
            get { return pluginMenu; }
        }

        /// <summary>
        /// Gets state circle
        /// </summary>
        public Ellipse StateCircle
        {
            get { return stateCircle; }
        }

        /// <summary>
        /// Delegate method for MouseLeftButtonDown event. Method handles Window moving if mouse
        /// left button is down. It handles double-click to maximize window.
        /// </summary>
        /// <param name="sender">object which raises event</param>
        /// <param name="e">event arguments</param>
        private void Window_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            this.DragMove();

            if (e.ClickCount == 2)
            {
                if (this.WindowState == WindowState.Normal)
                    this.WindowState = WindowState.Maximized;
                else
                    this.WindowState = WindowState.Normal;
            }
        }     

        /// <summary>
        /// Delegate method for  MouseLeftButtonUp event. It handles minimize button click.
        /// </summary>
        /// <param name="sender">object which raises event</param>
        /// <param name="e">event arguments</param>
        private void Minimize_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            this.WindowState = WindowState.Minimized;
        }

        /// <summary>
        /// Delegate method for MouseLeftButtonUp event. It handles maximize button click.
        /// </summary>
        /// <param name="sender">object which raises event</param>
        /// <param name="e">event arguments</param>
        private void Maximize_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (WindowState == WindowState.Maximized)
                this.WindowState = WindowState.Normal; 
            else
                this.WindowState = WindowState.Maximized;
        }

        /// <summary>
        /// Delegate method for MouseLeftButtonUp event. It handles close button click.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Close_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            Application.Current.Shutdown();
        }

        /// <summary>
        /// Delegate method for MouseEnter event. It handles Minimize button MouseOver.
        /// </summary>
        /// <param name="sender">object which raises event</param>
        /// <param name="e">event arguments</param>
        private void Minimize_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
        {
            MinimizeButton.Fill = _OrangeBrush;
        }

        /// <summary>
        /// Delegate method for MouseEnter event. It handles Minimize button MouseLeave.
        /// </summary>
        /// <param name="sender">object which raises event</param>
        /// <param name="e">event arguments</param>
        private void Minimize_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            MinimizeButton.Fill = _WhiteBrush;
        }

        /// <summary>
        /// Delegate method for MouseEnter event. It handles Maximize button MouseOver.
        /// </summary>
        /// <param name="sender">object which raises event</param>
        /// <param name="e">event arguments</param>
        private void Maximize_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
        {
            MaximizeButton.Fill = _OrangeBrush;
        }

        /// <summary>
        /// Delegate method for MouseEnter event. It handles Maximize button MouseLeave.
        /// </summary>
        /// <param name="sender">object which raises event</param>
        /// <param name="e">event arguments</param>
        private void Maximize_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            MaximizeButton.Fill = _WhiteBrush;
        }

        /// <summary>
        /// Delegate method for MouseEnter event. It handles Close button MouseOver.
        /// </summary>
        /// <param name="sender">object which raises event</param>
        /// <param name="e">event arguments</param>
        private void Close_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
        {
            CloseButton.Fill = _OrangeBrush;
        }

        /// <summary>
        /// Delegate method for MouseEnter event. It handles Close button MouseLeave.
        /// </summary>
        /// <param name="sender">object which raises event</param>
        /// <param name="e">event arguments</param>
        private void Close_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            CloseButton.Fill = _WhiteBrush;
        }

        /// <summary>
        /// Delegate method for BraekPoint.Click event. It handles if the button is shown or not.
        /// </summary>
        /// <param name="sender">object which raises event</param>
        /// <param name="e">event arguments</param>
        private void BraekPoint_Click(object sender, RoutedEventArgs e)
        {
            TreeListViewItem treeViewItem = FindAncestorOrSelf<TreeListViewItem>((Button)sender) as TreeListViewItem;

            if (treeViewItem != null)
            {
                treeViewItem.IsChecked = !treeViewItem.IsChecked;
            }
        }

        /// <summary>
        /// Delegate method for BraekPoint.Loaded event. It handles when the line is first shown.
        /// </summary>
        /// <param name="sender">object which raises event</param>
        /// <param name="e">event arguments</param>
        private void BraekPoint_Loaded(object sender, RoutedEventArgs e)
        {
            Button button = sender as Button;

            TreeListViewItem treeViewItem = FindAncestorOrSelf<TreeListViewItem>(button) as TreeListViewItem;

            if (treeViewItem != null)
            {
                treeViewItem.BrakePointButton = button;

                // Sets if the button is transparent or not
                treeViewItem.BrakePointButton.Opacity = treeViewItem.IsChecked ? 1 : 0;
            }
        }

        /// <summary>
        /// Try to get parent of DependencyObject
        /// </summary>
        /// <param name="obj">object which the parent is looking for </param>
        /// <returns>DependencyObject Parent</returns>
        protected static DependencyObject GetParent(DependencyObject obj)
        {
            if (obj == null)
                return null;

            ContentElement contentElement = obj as ContentElement;

            if (contentElement != null)
            {
                // Try to find parent from content
                DependencyObject parent = ContentOperations.GetParent(contentElement);
                
                if (parent != null)
                    return parent;
                
                // Try to find parent from framework content
                FrameworkContentElement frameworkContentElement = contentElement as FrameworkContentElement;
                return frameworkContentElement != null ? frameworkContentElement.Parent : null;                

            }

            // Try to find parent from VisualTreeHelper
            return VisualTreeHelper.GetParent(obj);
        }

        /// <summary>
        /// Gets child of DependencyObject.
        /// </summary>
        /// <param name="obj">object which child is looking for</param>
        /// <param name="index">index of child</param>
        /// <returns>DependencyObject Child</returns>
        protected static DependencyObject GetChild(DependencyObject obj, int index) 
        {
            if (obj == null)
                return null;

            int childCount = VisualTreeHelper.GetChildrenCount(obj);
            DependencyObject child = VisualTreeHelper.GetChild(obj, index);
           
            return child;
        }

        /// <summary>
        /// Try to find ancestor of DependencyObject. If no ancestor found, returns DependencyObject itself.
        /// </summary>
        /// <typeparam name="T">Type of searched ancestor</typeparam>
        /// <param name="obj">object which ancestor is looking for</param>
        /// <returns>Ancestor or itself</returns>
        protected static T FindAncestorOrSelf<T>(DependencyObject obj)
            where T : DependencyObject
        {
            while (obj != null)
            {
                T objTest = obj as T;
                
                if (objTest != null)
                    return objTest;

                obj = GetParent(obj);
            }

            return null;
        }
        
        /// <summary>
        /// Delegate method for MenuItem.Click event. It handles Exit menu button click.
        /// </summary>
        /// <param name="sender">object which raises event</param>
        /// <param name="e">event arguments</param>
        private void Exit_Click(object sender, RoutedEventArgs e)
        {
            Application.Current.Shutdown();
        }

        /// <summary>
        /// Delegate method for MenuItem.Click event. It handles Open menu button click.
        /// </summary>
        /// <param name="sender">object which raises event</param>
        /// <param name="e">event arguments</param>
        private void Open_Click(object sender, RoutedEventArgs e)
        {
            _openDialog.ShowDialog();
        }

        /// <summary>
        /// Delegate method for EvaluateButton.Click event.
        /// </summary>
        /// <param name="sender">object which raises event</param>
        /// <param name="e">event arguments</param>
        private void evaluateButton_Click(object sender, RoutedEventArgs e)
        {
            Core.Instance.OnButtonClicked(Core.WindowButton.EvaluateButton);
        }

        /// <summary>
        /// Delegate method for BackButton.Click event.
        /// </summary>
        /// <param name="sender">object which raises event</param>
        /// <param name="e">event arguments</param>
        private void backButton_Click(object sender, RoutedEventArgs e)
        {
            Core.Instance.OnButtonClicked(Core.WindowButton.BackButton);
        }

        /// <summary>
        /// Delegate method for NextButton.Click event.
        /// </summary>
        /// <param name="sender">object which raises event</param>
        /// <param name="e">event arguments</param>
        private void nextButton_Click(object sender, RoutedEventArgs e)
        {
            Core.Instance.OnButtonClicked(Core.WindowButton.NextButton);
        }
 	}
}